package com.lechi.web.controller;

import cn.hutool.core.util.ZipUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Maps;
import com.lechi.web.common.annotation.Anonymous;
import com.lechi.web.common.config.LeChiConfig;
import com.lechi.web.common.core.controller.BaseController;
import com.lechi.web.common.core.domain.AjaxResult;
import com.lechi.web.common.core.page.PageDomain;
import com.lechi.web.common.core.page.TableDataInfo;
import com.lechi.web.common.core.page.TableSupport;
import com.lechi.web.common.enums.ErrorCodeEnum;
import com.lechi.web.common.exception.ServiceException;
import com.lechi.web.common.utils.DateUtils;
import com.lechi.web.common.utils.StringUtils;
import com.lechi.web.common.utils.http.HttpUtils;
import com.lechi.web.common.utils.poi.ExcelUtil;
import com.lechi.web.common.utils.sql.SqlUtil;
import com.lechi.web.export.IotMonitorDataExport;
import com.lechi.web.job.GetSensorDataJob;
import com.lechi.web.service.IIotDeviceService;
import com.lechi.web.service.IIotMonitorDataService;
import com.lechi.web.service.IIotSensorRecordService;
import com.lechi.web.system.domain.*;
import com.lechi.web.vo.IotAnalysisDataQueryVo;
import com.lechi.web.vo.IotMonitorDataExportVo;
import com.lechi.web.vo.IotMonitorDataQueryVo;
import com.lechi.web.vo.IotMonitorExportResultVo;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.io.IOUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.util.*;
import java.util.concurrent.CompletableFuture;

/**
 * 监测数据Controller
 *
 * @author yangguang
 */
@Slf4j
@RestController
@RequestMapping("/iot/data")
@RequiredArgsConstructor
public class IotMonitorDataController extends BaseController {

    private final IIotMonitorDataService iotMonitorDataService;

    private final IIotDeviceService iotDeviceService;

    @Autowired
    private IIotSensorRecordService iIotSensorRecordService;

    /**
     * 查询监测数据列表
     *
     * @param iotMonitorDataQueryVo the iot monitor data query vo
     * @return the table data info
     */
    @GetMapping("/list")
    @Anonymous
    //    @PreAuthorize("@ss.hasPermi('iot:cmd:query')")
    public TableDataInfo list(IotMonitorDataQueryVo iotMonitorDataQueryVo) {
        startPage();
        // 获取当前的用户名称
        IotMonitorDataBo iotMonitorDataBo = new IotMonitorDataBo();
        BeanUtils.copyProperties(iotMonitorDataQueryVo, iotMonitorDataBo);
        iotMonitorDataBo.setTableName("iot_monitor_data_" + iotMonitorDataQueryVo.getDeviceId());
        List<IotMonitorDataBo> list = iotMonitorDataService.selectIotMonitorDataList(iotMonitorDataBo);
        return getDataTable(list);
    }

    /**
     * 查询监测数据列表
     *
     * @param iotMonitorDataQueryVo the iot monitor data query vo
     * @return the table data info
     */
    @Anonymous
    @GetMapping("/downloader")
    //    @PreAuthorize("@ss.hasPermi('iot:cmd:query')")
    public TableDataInfo downloader(IotMonitorDataQueryVo iotMonitorDataQueryVo) {
        startPage();
        final Date beginTime = DateUtils.parseDate(iotMonitorDataQueryVo.getParams().get("beginTime"));
        final Date endTime = DateUtils.parseDate(iotMonitorDataQueryVo.getParams().get("endTime"));
        if (!beginTime.before(endTime)) {
            throw new ServiceException(ErrorCodeEnum.DATE_TIME_ERROR.getValue(), ErrorCodeEnum.DATE_TIME_ERROR.getKey());
        }
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("tableName", "iot_monitor_data_" + iotMonitorDataQueryVo.getDeviceId());
        paramMap.put("timeFormat", getTimeFormat("minute"));
        paramMap.put("sensorAliasId", iotMonitorDataQueryVo.getSensorAliasId());
        paramMap.put("beginTime", beginTime);
        paramMap.put("endTime", endTime);
        Map<String, IotSensorValue> sensorValueMap = iotMonitorDataService.formatTimeExportMonitorData(iotMonitorDataQueryVo.getQueryType(), paramMap);
        List<IotMonitorExportResultVo> list = Lists.newArrayList();
        if (sensorValueMap == null || sensorValueMap.isEmpty()) {
            return getDataTable(list);
        }
        long internal = iotMonitorDataQueryVo.getInternalTime() == null ? 1 : iotMonitorDataQueryVo.getInternalTime();
        long total = (endTime.getTime() - beginTime.getTime()) / (60000 * internal);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(beginTime);
        for (int i = 1; i <= total; i = i + 1) {
            if (calendar.after(endTime)) {
                break;
            }
            IotMonitorExportResultVo resultVo = new IotMonitorExportResultVo();
            resultVo.setT(DateUtils.dateTime(calendar.getTime()));
            IotSensorValue iotSensorValue = sensorValueMap.get(resultVo.getT());
            resultVo.setV(iotSensorValue == null ? "" : iotSensorValue.getV());
            calendar.setTimeInMillis(beginTime.getTime() + i * 60000L * internal);
            list.add(resultVo);
        }
        return getDataTable(list);
    }

    /**
     * 查询监测数据列表
     *
     * @param iotAnalysisDataQueryVo the iot monitor data query vo
     * @return the table data info
     */
    @Anonymous
    @PostMapping("/dataAnalysis")
    //    @PreAuthorize("@ss.hasPermi('iot:cmd:query')")
    public AjaxResult dataAnalysis(@RequestBody @Valid IotAnalysisDataQueryVo iotAnalysisDataQueryVo) {
        Date beginTime = iotAnalysisDataQueryVo.getBeginTime();
        Date endTime = iotAnalysisDataQueryVo.getEndTime();
        if (!beginTime.before(endTime)) {
            throw new ServiceException(ErrorCodeEnum.DATE_TIME_ERROR.getValue(), ErrorCodeEnum.DATE_TIME_ERROR.getKey());
        }

        Map<Object, List<IotSensorValue>> map = Maps.newHashMap();
        final List list = JSON.parseObject(iotAnalysisDataQueryVo.getSensors(), List.class);
        List<CompletableFuture<Void>> futureList = Lists.newArrayList();
        for (Object object : list) {
            Map<String, Object> paramMap = new HashMap<>();
            paramMap.put("tableName", "iot_monitor_data_" + iotAnalysisDataQueryVo.getDeviceId());
            paramMap.put("timeFormat", getTimeFormat(iotAnalysisDataQueryVo.getInternalType()));
            paramMap.put("beginTime", beginTime);
            paramMap.put("endTime", endTime);
            JSONObject sensors = (JSONObject) object;
            paramMap.put("queryType", sensors.get("queryType"));
            paramMap.put("sensorAliasId", sensors.get("sensorAliasId"));
            futureList.add(CompletableFuture.supplyAsync(() -> iotMonitorDataService.selectDataAnalysisData(paramMap))
                    .thenAccept(sensorValueList -> {
                        map.put(paramMap.get("sensorAliasId"), sensorValueList);
                    }));
        }
        // 使用allOf等待所有CompletableFuture完成，它返回一个CompletableFuture<Void>
        CompletableFuture<Void> allFutures = CompletableFuture.allOf(futureList.toArray(new CompletableFuture[0]));
        allFutures.join();
        return success(map);
    }


    private String getTimeFormat(String internalTime) {
        //年：1， 月：2 日：3 时：4 分：5
        return switch (internalTime) {
            case "year" -> "'%Y'";
            case "month" -> "'%Y-%m'";
            case "day" -> "'%Y-%m-%d'";
            case "hour" -> "'%Y-%m-%d %H'";
            case "minute" -> "'%Y-%m-%d %H:%i'";
            default -> "'%Y-%m-%d %H:%i:%s'";
        };
    }

    /**
     * 查询监测数据列表
     *
     * @param iotMonitorDataQueryVo the iot monitor data query vo
     * @return the ajax result
     */
    @GetMapping("/count")
    //    @PreAuthorize("@ss.hasPermi('iot:cmd:query')")
    public AjaxResult count(IotMonitorDataQueryVo iotMonitorDataQueryVo) {
        IotMonitorDataBo iotMonitorDataBo = new IotMonitorDataBo();
        BeanUtils.copyProperties(iotMonitorDataQueryVo, iotMonitorDataBo);
        iotMonitorDataBo.setTableName("iot_monitor_data_" + iotMonitorDataQueryVo.getDeviceId());
        IotMonitorDataCountBo iotMonitorDataCount = iotMonitorDataService.selectIotMonitorDataCount(iotMonitorDataBo);
        return AjaxResult.success(iotMonitorDataCount);
    }

    /**
     * 获取临潼站数据
     *
     * @return the lc 001
     */
    @Anonymous
    @GetMapping("/getLC001")
    public AjaxResult getLC001() {
        final String deviceLC001 = HttpUtils.sendSSLPost("https://www.dtuip.com/queryUserAllSensorDatas.htm", "userId=93065&deviceIds=251835");
        final JSONObject deviceJSON1 = JSON.parseObject(deviceLC001);
        final JSONArray senLastDataList = deviceJSON1.getJSONArray("senLastDataList");
        return getResult(senLastDataList);
    }

    /**
     * 获取临潼站数据
     *
     * @return the lc 002
     */
    @Anonymous
    @GetMapping("/getLC002")
    public AjaxResult getLC002() {
        final String deviceLC002 = HttpUtils.sendSSLPost("https://www.dtuip.com/queryUserAllSensorDatas.htm", "userId=93065&deviceIds=275600");
        final JSONObject deviceJSON2 = JSON.parseObject(deviceLC002);
        final JSONArray senLastDataList = deviceJSON2.getJSONArray("senLastDataList");
        return getResult(senLastDataList);
    }

    /**
     * 获取临潼站数据
     *
     * @return the lc 002
     */
    @Anonymous
    @GetMapping("/getXY")
    public AjaxResult getCity() {
        final String deviceLC002 = HttpUtils.sendSSLPost("https://www.dtuip.com/queryUserAllSensorDatas.htm", "userId=106186&deviceIds=331408");
        final JSONObject deviceJSON2 = JSON.parseObject(deviceLC002);
        final JSONArray senLastDataList = deviceJSON2.getJSONArray("senLastDataList");
        return getResult(senLastDataList);
    }

    /**
     * Gets result.
     *
     * @param senLastDataList the sen last data list
     * @return the result
     */
    @NotNull
    public AjaxResult getResult(JSONArray senLastDataList) {
        List<JSONObject> jsonObjectList = Lists.newArrayList();
        senLastDataList.forEach(sensor -> {
            JSONObject sensorObj = (JSONObject) sensor;
            JSONObject target = new JSONObject();
            final Object sensorId = sensorObj.get("sensorId");
            // 4291312最后计算时间的排除掉 4782480
            if (!"4291312".equals(sensorId) && !"4782480".equals(sensorId)) {
                target.put("sensorId", sensorId);
                target.put("val", sensorObj.get("val"));
                target.put("unit", GetSensorDataJob.map.getOrDefault("unit_" + sensorId, String.valueOf(sensorObj.get("unit"))));
                target.put("name", GetSensorDataJob.map.get(sensorId));
                jsonObjectList.add(target);
            }
        });
        return AjaxResult.success(jsonObjectList);
    }

    /**
     * 导出监测数据列表
     *
     * @param response         the response
     * @param iotMonitorDataVo the iot monitor data vo
     */
    @PostMapping("/export")
    //    @PreAuthorize("@ss.hasPermi('iot:cmd:query')")
    public void export(HttpServletResponse response, @RequestBody IotMonitorDataExportVo iotMonitorDataVo) {
        PageDomain pageDomain = TableSupport.buildPageRequest();
        Integer pageNum = pageDomain.getPageNum();
        Integer pageSize = pageDomain.getPageSize();
        if (pageNum == null || pageSize == null) {
            pageNum = 1;
            pageSize = 20000;
        }
        if (pageSize > 20000) {
            throw new ServiceException(ErrorCodeEnum.PAGE_SIZE_ERROR.getValue(), ErrorCodeEnum.PAGE_SIZE_ERROR.getKey());
        }
        String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
        Boolean reasonable = pageDomain.getReasonable();
        PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable);

        IotMonitorDataBo iotMonitorDataBo = new IotMonitorDataBo();
        BeanUtils.copyProperties(iotMonitorDataVo, iotMonitorDataBo);
        Map<String, Object> hashMap = new HashMap<>();
        hashMap.put("beginTime", iotMonitorDataVo.getBeginTime());
        hashMap.put("endTime", iotMonitorDataVo.getEndTime());

        String deviceSN = iotMonitorDataVo.getDeviceSN();
        IotDeviceBo iotDeviceBo = new IotDeviceBo();
        iotDeviceBo.setDeviceSn(deviceSN);
        List<IotDeviceBo> iotDeviceBoList = iotDeviceService.selectIotDeviceList(iotDeviceBo);
        if (iotDeviceBoList.isEmpty()) {
            throw new ServiceException(ErrorCodeEnum.NOEXITS_ERROR.getValue(), ErrorCodeEnum.NOEXITS_ERROR.getKey());
        }
        iotDeviceBo = iotDeviceBoList.get(0);
        iotMonitorDataBo.setDeviceId(iotDeviceBo.getId());
        iotMonitorDataBo.setParams(hashMap);
        iotMonitorDataBo.setTableName("iot_monitor_data_" + iotDeviceBo.getId());
        iotMonitorDataBo.setSensorAliasId(iotMonitorDataVo.getSensorAliasId());
        List<IotMonitorDataBo> list = iotMonitorDataService.exportIotMonitorDataList(iotMonitorDataBo);
        if (list == null || list.isEmpty()) {
            throw new ServiceException(ErrorCodeEnum.NOEXITS_ERROR.getValue(), ErrorCodeEnum.NOEXITS_ERROR.getKey());
        }
        List<IotMonitorDataExport> exportList = Lists.newArrayList();
        list.forEach(iotMonitorDataBo1 -> {
            IotMonitorDataExport iotMonitorDataExport = new IotMonitorDataExport();
            BeanUtils.copyProperties(iotMonitorDataBo1, iotMonitorDataExport);
            exportList.add(iotMonitorDataExport);
        });
        ExcelUtil<IotMonitorDataExport> util = new ExcelUtil<>(IotMonitorDataExport.class);
        util.exportExcel(response, exportList, "监测数据");
    }

    /**
     * 导出监测数据记录
     *
     * @param response the response
     */
    @PostMapping("/download")
    //    @PreAuthorize("@ss.hasPermi('iot:cmd:query')")
    public void exportZip(HttpServletResponse response, @RequestBody IotMonitorDataExportVo iotMonitorDataExportVo) {

        IotSensorRecordBo IotSensorRecordBo = new IotSensorRecordBo();
        IotSensorRecordBo.setDeviceId(iotMonitorDataExportVo.getDeviceId());
        Map<String, Object> hashMap = new HashMap<>();
        hashMap.put("beginTime", iotMonitorDataExportVo.getBeginTime());
        hashMap.put("endTime", iotMonitorDataExportVo.getEndTime());
        IotSensorRecordBo.setParams(hashMap);

        List<IotSensorRecordBo> list = iIotSensorRecordService.selectIotSensorRecordList(IotSensorRecordBo);
        if (list.isEmpty()) {
            throw new ServiceException(ErrorCodeEnum.NOEXITS_ERROR.getValue(), ErrorCodeEnum.NOEXITS_ERROR.getKey());
        }
        String fileName = StringUtils.format("{}_{}.zip", "设备ID", iotMonitorDataExportVo.getDeviceId());
        File zipFile = new File(LeChiConfig.getRecordLogPath() + fileName);
        try {
            List<File> fileList = list.stream().map(sensorRecordBo -> new File(sensorRecordBo.getFilepath())).toList();
            ZipUtil.zip(zipFile, false, fileList.toArray(new File[0]));
            response.reset();
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/octet-stream; charset=UTF-8");
            response.setHeader("Content-Disposition", "attachment; filename=" + zipFile.getName());
            BufferedInputStream fis = new BufferedInputStream(new FileInputStream(zipFile.getPath()));
            byte[] buffer = new byte[fis.available()];
            fis.read(buffer);
            fis.close();
            IOUtils.write(buffer, response.getOutputStream());
        } catch (Exception e) {
            log.error("下载zip压缩包过程发生异常:", e);
        } finally {
            zipFile.delete();
        }
    }

    /**
     * 删除监测数据  暂时没有使用
     *
     * @param ids the ids
     * @return the ajax result
     */
    @DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable Long[] ids) {
        iotMonitorDataService.deleteIotMonitorDataByIds(ids);
        return AjaxResult.success();
    }
}
